package cn.iocoder.yudao.module.promotion.coupon.controller.app;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.api.promotion.coupon.dto.CouponRespDTO;
import cn.iocoder.yudao.module.api.promotion.coupon.enums.CouponTakeTypeEnum;
import cn.iocoder.yudao.module.api.shop.info.ShopInfoApi;
import cn.iocoder.yudao.module.api.shop.info.dto.ShopInfoDTO;
import cn.iocoder.yudao.module.promotion.coupon.convert.CouponRecordConvert;
import cn.iocoder.yudao.module.promotion.coupon.dal.dataobject.CouponRecordDO;
import cn.iocoder.yudao.module.promotion.coupon.dal.dataobject.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.coupon.service.CouponRecordService;
import cn.iocoder.yudao.module.promotion.coupon.service.CouponTemplateService;
import cn.iocoder.yudao.module.promotion.coupon.vo.*;
import cn.iocoder.yudao.module.promotion.gift.pojo.dto.AppGiftVerifyDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

@Tag(name = "用户 App - 优惠劵领取记录")
@RestController
@RequestMapping("/promotion/coupon")
@Validated
public class AppCouponRecordController {

    @Resource
    private CouponRecordService couponRecordService;
    @Resource
    private CouponTemplateService couponTemplateService;

    @Resource
    private ShopInfoApi shopInfoApi;

    @PostMapping("/take")
    @Operation(summary = "领取优惠劵")
    @Parameter(name = "templateId", description = "优惠券模板编号", required = true, example = "1024")
    public CommonResult<Boolean> takeCoupon(@Valid @RequestBody AppCouponTakeReqVO reqVO) {
        // 1. 领取优惠劵
        Long userId = getLoginUserId();
        couponRecordService.takeCoupon(reqVO.getTemplateId(), CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER);

        // 2. 检查是否可以继续领取
        CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(reqVO.getTemplateId());
        boolean canTakeAgain = true;
        if (couponTemplate.getTakeLimitCount() != null && couponTemplate.getTakeLimitCount() > 0) {
            Integer takeCount = couponRecordService.getTakeCount(reqVO.getTemplateId(), userId);
            canTakeAgain = takeCount < couponTemplate.getTakeLimitCount();
        }
        return success(canTakeAgain);
    }

    @GetMapping("/get-by-verify-code")
    @Operation(summary = "查询核销码对应的优惠券")
    @Parameter(name = "verifyCode", description = "核销码")
    @PreAuthorize("@mm.isMerchant()")
    public CommonResult<CouponRespDTO> getByVerifyCode(@RequestParam("verifyCode") String verifyCode) {
        return success(couponRecordService.getByVerifyCode(getLoginUserId(), UserTypeEnum.MEMBER.getValue(), verifyCode));
    }

    @Operation(summary = "核销优惠券")
    @PostMapping("/verify")
    @Parameter(name = "verifyCode", description = "核销码")
    @PreAuthorize("@mm.isMerchant()")
    public CommonResult<Boolean> verify(@RequestParam(value = "verifyCode", required = false) String verifyCode, @RequestBody AppGiftVerifyDTO reqVO) {
        String code = reqVO.getVerifyCode();
        if (StrUtil.isBlank(code)) {
            code = verifyCode;
        }
        if (StrUtil.isBlank(code)) {
            return error(BAD_REQUEST.getCode(), "核销码不能为空");
        }
        couponRecordService.verifyByMerchant(getLoginUserId(), verifyCode);
        return success(true);
    }

    @GetMapping("/page")
    @Operation(summary = "我的优惠劵列表")
    public CommonResult<PageResult<AppCouponListRespVO>> getCouponPage(AppCouponPageReqVO pageReqVO) {
        CouponRecordPageReqVO reqVO = CouponRecordConvert.INSTANCE.convert(pageReqVO, Collections.singleton(getLoginUserId()));
        PageResult<CouponRecordDO> pageResult = couponRecordService.getCouponPage(reqVO);
        PageResult<AppCouponItemRespVO> data = BeanUtils.toBean(pageResult, AppCouponItemRespVO.class);
        List<AppCouponItemRespVO> list = data.getList();
        if (CollUtil.isEmpty(list)) {
            return success(PageResult.empty());
        }
        Map<Long, ShopInfoDTO> shops = shopInfoApi.getShopInfoMap(convertSet(list, AppCouponItemRespVO::getShopId));
        // 按店铺分组
        Map<Long, List<AppCouponItemRespVO>> groupByShop = new HashMap<>();
        for (AppCouponItemRespVO it : list) {
            groupByShop.computeIfAbsent(it.getShopId(), k -> new ArrayList<>()).add(it);
        }
        // 转换数据格式
        List<AppCouponListRespVO> respVOS = new ArrayList<>();
        for (Map.Entry<Long, List<AppCouponItemRespVO>> entry : groupByShop.entrySet()) {
            AppCouponListRespVO respVO = new AppCouponListRespVO();
            respVO.setShopId(entry.getKey());
            respVO.setShop(shops.get(entry.getKey()));
            respVO.setItems(entry.getValue());
            respVOS.add(respVO);
        }
        PageResult<AppCouponListRespVO> page = new PageResult<>(respVOS, pageResult.getTotal());
        return success(page);
    }

    @GetMapping("/get")
    @Operation(summary = "获得优惠劵")
    @Parameter(name = "id", description = "优惠劵编号", required = true, example = "1024")
    public CommonResult<AppCouponItemRespVO> getCoupon(@RequestParam("id") Long id) {
        CouponRecordDO coupon = couponRecordService.getCoupon(getLoginUserId(), id);
        return success(BeanUtils.toBean(coupon, AppCouponItemRespVO.class));
    }

    @GetMapping(value = "/get-unused-count")
    @Operation(summary = "获得未使用的优惠劵数量")
    public CommonResult<Integer> getUnusedCouponCount() {
        return success(couponRecordService.getUnusedCouponCount(getLoginUserId()));
    }

}
